package top.yaofengqiao.springcloudsimple.auth.biz.domain.security.provider;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.auth.model.entity.RefreshTokenEntity;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.auth.model.valobj.UserType;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.auth.service.IOauthTokenService;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.security.model.RefreshTokenAuthenticationToken;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.security.model.UserInfo;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.user.service.IMemberService;
import top.yaofengqiao.springcloudsimple.auth.biz.domain.user.service.IUserService;
import top.yaofengqiao.springcloudsimple.auth.biz.trigger.http.dto.RefreshTokenDTO;
import top.yaofengqiao.springcloudsimple.common.constant.ResponseCode;
import top.yaofengqiao.springcloudsimple.common.util.AppException;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @author yfq
 * @date 2024/6/7 11:56
 * @description refreshToken认证
 */
@Component
public class RefreshTokenAuthenticationProvider implements AuthenticationProvider {
    @Resource
    private IOauthTokenService oauthTokenService;
    @Resource
    private UserDetailsService adminUserDetailService;
    @Resource
    private UserDetailsService memberUserDetailService;
    @Resource
    private IUserService userService;
    @Resource
    private IMemberService memberService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        RefreshTokenAuthenticationToken refreshTokenAuthenticationToken = (RefreshTokenAuthenticationToken) authentication;
        RefreshTokenDTO refreshTokenDTO = (RefreshTokenDTO) refreshTokenAuthenticationToken.getCredentials();

        // 1. TODO 验证clientSecret

        // 2. 查询refreshToken
        RefreshTokenEntity refreshTokenEntity = oauthTokenService.queryRefreshToken(refreshTokenDTO.getRefreshToken());

        // 3. 无效refreshToken
        if (refreshTokenEntity == null) throw new AppException(ResponseCode.INVALID_TOKEN);

        // 4. token过期
        LocalDateTime expires = refreshTokenEntity.getExpiresTime();
        if (expires.isBefore(LocalDateTime.now())) throw new AppException(ResponseCode.INVALID_TOKEN);

        // 5. clientId不一致
        if (!refreshTokenEntity.getClientId().equals(refreshTokenDTO.getClientId()))
            throw new AppException(ResponseCode.DEVICE_EXCEPTION);

        // 6. 查询userDetails
        UserType type = UserType.determineUserType(refreshTokenEntity.getUserType());
        UserDetails userDetails;
        if (type == UserType.MEMBER) {
            String username = memberService.queryById(refreshTokenEntity.getUserId()).getMobile();
            userDetails = memberUserDetailService.loadUserByUsername(username);
        } else {
            String username = userService.queryById(refreshTokenEntity.getUserId()).getUsername();
            userDetails = adminUserDetailService.loadUserByUsername(username);
        }

        // 账号状态检查
        boolean accountNonLocked = userDetails.isAccountNonLocked();
        if (!accountNonLocked) throw new LockedException("User account is locked");

        refreshTokenAuthenticationToken.setUserInfo((UserInfo) userDetails);

        return refreshTokenAuthenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return RefreshTokenAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
